<template>
  <div class="gpu-compute-container">
    <!-- 主渲染区域 -->
    <canvas ref="computeCanvas" class="compute-canvas"></canvas>

    <!-- 控制面板 -->
    <div class="control-panel">
      <div class="panel-section">
        <h3>GPU计算控制台</h3>

        <div class="hardware-info">
          <div class="info-item">
            <span class="label">WebGPU支持:</span>
            <span class="value" :class="{'supported': gpuSupported}">
              {{ gpuSupported ? '可用' : '不可用' }}
            </span>
          </div>
          <div class="info-item" v-if="gpuSupported">
            <span class="label">计算单元:</span>
            <span class="value">{{ computeUnits }} units</span>
          </div>
        </div>

        <div class="compute-actions">
          <button
            @click="runParticleSimulation()"
            :disabled="!gpuSupported || isComputing"
            class="compute-button"
          >
            🚀 运行粒子模拟
          </button>

          <button
            @click="runMatrixMultiplication()"
            :disabled="!gpuSupported || isComputing"
            class="compute-button"
          >
            ⚡ 矩阵运算
          </button>

          <button
            @click="runImageProcessing()"
            :disabled="!gpuSupported || isComputing"
            class="compute-button"
          >
            🎨 图像处理
          </button>
        </div>
      </div>

      <div class="panel-section">
        <h4>性能监控</h4>
        <div class="performance-stats">
          <div class="stat">
            <span class="stat-label">计算时间:</span>
            <span class="stat-value">{{ computeTime }}ms</span>
          </div>
          <div class="stat">
            <span class="stat-label">数据规模:</span>
            <span class="stat-value">{{ dataSize }} elements</span>
          </div>
          <div class="stat">
            <span class="stat-label">GPU负载:</span>
            <span class="stat-value">{{ gpuLoad }}%</span>
          </div>
        </div>
      </div>

      <div class="panel-section">
        <h4>计算参数</h4>
        <div class="parameter-controls">
          <div class="param-group">
            <label>粒子数量: {{ particleCount }}</label>
            <input
              type="range"
              v-model="particleCount"
              min="1000"
              max="1000000"
              step="1000"
            >
          </div>

          <div class="param-group">
            <label>工作组大小: {{ workgroupSize }}</label>
            <select v-model="workgroupSize">
              <option value="64">64 线程/组</option>
              <option value="128">128 线程/组</option>
              <option value="256">256 线程/组</option>
            </select>
          </div>
        </div>
      </div>
    </div>

    <!-- 加载状态 -->
    <div v-if="isComputing" class="compute-status">
      <div class="spinner"></div>
      <span>GPU计算中... {{ computeProgress }}%</span>
    </div>
  </div>
</template>

<script>
import { onMounted, onUnmounted, ref, reactive } from 'vue';

export default {
  name: 'GPUComputeDemo',
  setup() {
    const computeCanvas = ref(null);
    const gpuSupported = ref(false);
    const isComputing = ref(false);
    const computeTime = ref(0);
    const dataSize = ref(0);
    const gpuLoad = ref(0);
    const computeProgress = ref(0);
    const particleCount = ref(10000);
    const workgroupSize = ref(64);
    const computeUnits = ref(0);

    let device = null;
    let context = null;
    let commandEncoder = null;
    let computePipeline = null;

    // 初始化WebGPU环境
    const initWebGPU = async () => {
      try {
        // 检测WebGPU支持
        if (!navigator.gpu) {
          throw new Error('WebGPU not supported');
        }

        // 请求适配器
        const adapter = await navigator.gpu.requestAdapter();
        if (!adapter) {
          throw new Error('No GPU adapter found');
        }

        // 获取设备信息
        computeUnits.value = adapter.limits.maxComputeInvocationsPerWorkgroup;

        // 请求设备
        device = await adapter.requestDevice();

        // 设置画布上下文
        context = computeCanvas.value.getContext('webgpu');
        const canvasFormat = navigator.gpu.getPreferredCanvasFormat();

        context.configure({
          device: device,
          format: canvasFormat,
          alphaMode: 'premultiplied'
        });

        gpuSupported.value = true;
        console.log('WebGPU初始化成功');

      } catch (error) {
        console.error('WebGPU初始化失败:', error);
        gpuSupported.value = false;
      }
    };

    // 创建计算管线
    const createComputePipeline = async (shaderCode, bindGroupLayout) => {
      const shaderModule = device.createShaderModule({
        code: shaderCode
      });

      return device.createComputePipeline({
        layout: device.createPipelineLayout({
          bindGroupLayouts: [bindGroupLayout]
        }),
        compute: {
          module: shaderModule,
          entryPoint: 'main'
        }
      });
    };

    // 粒子模拟计算着色器
    const particleComputeShader = `
      @group(0) @binding(0) var<storage, read_write> particlesIn: array<vec4<f32>>;
      @group(0) @binding(1) var<storage, read_write> particlesOut: array<vec4<f32>>;
      @group(0) @binding(2) var<uniform> params: vec4<f32>;

      @compute @workgroup_size(${workgroupSize.value})
      fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
        let index = global_id.x;
        if (index >= ${particleCount.value}) {
          return;
        }

        var particle = particlesIn[index];
        var position = particle.xyz;
        var velocity = particle.w;

        // 简单的物理模拟
        velocity += params.x * 0.016; // 重力
        position.y += velocity;

        // 地面碰撞检测
        if (position.y < -1.0) {
          position.y = -1.0;
          velocity = -velocity * 0.8; // 弹性碰撞
        }

        particlesOut[index] = vec4<f32>(position, velocity);
      }
    `;

    // 运行粒子模拟
    const runParticleSimulation = async () => {
      if (!device || isComputing.value) return;

      isComputing.value = true;
      computeProgress.value = 0;
      const startTime = performance.now();

      try {
        // 创建粒子数据
        const particleData = new Float32Array(particleCount.value * 4);
        for (let i = 0; i < particleCount.value; i++) {
          const offset = i * 4;
          particleData[offset] = (Math.random() - 0.5) * 2; // x
          particleData[offset + 1] = Math.random() * 2;     // y
          particleData[offset + 2] = (Math.random() - 0.5) * 2; // z
          particleData[offset + 3] = 0; // velocity
        }

        // 创建GPU缓冲区
        const inputBuffer = device.createBuffer({
          size: particleData.byteLength,
          usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
          mappedAtCreation: true
        });
        new Float32Array(inputBuffer.getMappedRange()).set(particleData);
        inputBuffer.unmap();

        const outputBuffer = device.createBuffer({
          size: particleData.byteLength,
          usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC
        });

        const paramsBuffer = device.createBuffer({
          size: 16,
          usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
        });

        // 创建绑定组布局
        const bindGroupLayout = device.createBindGroupLayout({
          entries: [
            {
              binding: 0,
              visibility: GPUShaderStage.COMPUTE,
              buffer: { type: 'storage' }
            },
            {
              binding: 1,
              visibility: GPUShaderStage.COMPUTE,
              buffer: { type: 'storage' }
            },
            {
              binding: 2,
              visibility: GPUShaderStage.COMPUTE,
              buffer: { type: 'uniform' }
            }
          ]
        });

        // 创建绑定组
        const bindGroup = device.createBindGroup({
          layout: bindGroupLayout,
          entries: [
            { binding: 0, resource: { buffer: inputBuffer } },
            { binding: 1, resource: { buffer: outputBuffer } },
            { binding: 2, resource: { buffer: paramsBuffer } }
          ]
        });

        // 创建计算管线
        computePipeline = await createComputePipeline(particleComputeShader, bindGroupLayout);

        // 创建命令编码器
        commandEncoder = device.createCommandEncoder();

        // 开始计算通道
        const computePass = commandEncoder.beginComputePass();
        computePass.setPipeline(computePipeline);
        computePass.setBindGroup(0, bindGroup);

        // 分发计算任务
        const workgroupCount = Math.ceil(particleCount.value / workgroupSize.value);
        computePass.dispatchWorkgroups(workgroupCount);
        computePass.end();

        // 提交命令
        device.queue.submit([commandEncoder.finish()]);

        // 读取结果
        await readComputeResults(outputBuffer, particleData.byteLength);

        const endTime = performance.now();
        computeTime.value = (endTime - startTime).toFixed(2);
        dataSize.value = particleCount.value;
        gpuLoad.value = Math.min(100, Math.round((particleCount.value / 100000) * 100));

      } catch (error) {
        console.error('粒子模拟失败:', error);
      } finally {
        isComputing.value = false;
        computeProgress.value = 100;
      }
    };

    // 读取计算结果
    const readComputeResults = async (outputBuffer, size) => {
      // 创建暂存缓冲区
      const stagingBuffer = device.createBuffer({
        size: size,
        usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
      });

      commandEncoder = device.createCommandEncoder();
      commandEncoder.copyBufferToBuffer(outputBuffer, 0, stagingBuffer, 0, size);

      device.queue.submit([commandEncoder.finish()]);

      // 映射缓冲区读取数据
      await stagingBuffer.mapAsync(GPUMapMode.READ);
      const results = new Float32Array(stagingBuffer.getMappedRange());
      stagingBuffer.unmap();

      console.log('计算结果:', results.slice(0, 8));
      return results;
    };

    // 矩阵乘法示例
    const runMatrixMultiplication = async () => {
      if (!device || isComputing.value) return;

      isComputing.value = true;
      const startTime = performance.now();

      try {
        const matrixSize = 1024;
        const totalElements = matrixSize * matrixSize;

        // 创建矩阵数据
        const matrixA = new Float32Array(totalElements);
        const matrixB = new Float32Array(totalElements);

        for (let i = 0; i < totalElements; i++) {
          matrixA[i] = Math.random();
          matrixB[i] = Math.random();
        }

        // 创建GPU缓冲区
        const bufferA = createGPUBuffer(matrixA, GPUBufferUsage.STORAGE);
        const bufferB = createGPUBuffer(matrixB, GPUBufferUsage.STORAGE);
        const bufferResult = device.createBuffer({
          size: matrixA.byteLength,
          usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC
        });

        // 矩阵乘法着色器
        const matrixShader = `
          @group(0) @binding(0) var<storage, read> matrixA: array<f32>;
          @group(0) @binding(1) var<storage, read> matrixB: array<f32>;
          @group(0) @binding(2) var<storage, read_write> matrixC: array<f32>;

          @compute @workgroup_size(16, 16)
          fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
            let row = global_id.y;
            let col = global_id.x;

            if (row >= ${matrixSize}u || col >= ${matrixSize}u) {
              return;
            }

            var sum = 0.0;
            for (var k = 0u; k < ${matrixSize}u; k = k + 1u) {
              let a = matrixA[row * ${matrixSize}u + k];
              let b = matrixB[k * ${matrixSize}u + col];
              sum = sum + a * b;
            }

            matrixC[row * ${matrixSize}u + col] = sum;
          }
        `;

        // 创建计算管线并执行
        const bindGroupLayout = device.createBindGroupLayout({
          entries: [
            { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: 'read-only-storage' } },
            { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: 'read-only-storage' } },
            { binding: 2, visibility: GPUShaderStage.COMPUTE, buffer: { type: 'storage' } }
          ]
        });

        const bindGroup = device.createBindGroup({
          layout: bindGroupLayout,
          entries: [
            { binding: 0, resource: { buffer: bufferA } },
            { binding: 1, resource: { buffer: bufferB } },
            { binding: 2, resource: { buffer: bufferResult } }
          ]
        });

        const pipeline = device.createComputePipeline({
          layout: device.createPipelineLayout({
            bindGroupLayouts: [bindGroupLayout]
          }),
          compute: {
            module: device.createShaderModule({ code: matrixShader }),
            entryPoint: 'main'
          }
        });

        const encoder = device.createCommandEncoder();
        const pass = encoder.beginComputePass();
        pass.setPipeline(pipeline);
        pass.setBindGroup(0, bindGroup);
        pass.dispatchWorkgroups(Math.ceil(matrixSize / 16), Math.ceil(matrixSize / 16));
        pass.end();

        device.queue.submit([encoder.finish()]);

        const endTime = performance.now();
        computeTime.value = (endTime - startTime).toFixed(2);
        dataSize.value = totalElements;
        gpuLoad.value = 85;

      } catch (error) {
        console.error('矩阵乘法失败:', error);
      } finally {
        isComputing.value = false;
      }
    };

    // 创建GPU缓冲区
    const createGPUBuffer = (data, usage) => {
      const buffer = device.createBuffer({
        size: data.byteLength,
        usage: usage | GPUBufferUsage.COPY_DST,
        mappedAtCreation: true
      });
      new (data.constructor)(buffer.getMappedRange()).set(data);
      buffer.unmap();
      return buffer;
    };

    // 图像处理示例
    const runImageProcessing = async () => {
      console.log('图像处理功能待实现');
      // 实现图像处理逻辑
    };

    onMounted(async () => {
      await initWebGPU();
    });

    onUnmounted(() => {
      // 清理资源
      if (device) {
        device.destroy();
      }
    });

    return {
      computeCanvas,
      gpuSupported,
      isComputing,
      computeTime,
      dataSize,
      gpuLoad,
      computeProgress,
      particleCount,
      workgroupSize,
      computeUnits,
      runParticleSimulation,
      runMatrixMultiplication,
      runImageProcessing
    };
  }
};
</script>

<style scoped>
.gpu-compute-container {
  width: 100%;
  height: 100vh;
  display: flex;
  background: #1a1a1a;
}

.compute-canvas {
  width: 70%;
  height: 100%;
  background: #000;
}

.control-panel {
  width: 30%;
  padding: 20px;
  background: #2a2a2a;
  color: white;
  overflow-y: auto;
}

.panel-section {
  margin-bottom: 30px;
}

.panel-section h3 {
  color: #00ffff;
  margin-bottom: 20px;
  border-bottom: 2px solid #00ffff;
  padding-bottom: 10px;
}

.panel-section h4 {
  color: #00ff88;
  margin-bottom: 15px;
}

.hardware-info {
  margin-bottom: 20px;
}

.info-item {
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
  padding: 8px;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 5px;
}

.value.supported {
  color: #00ff00;
}

.compute-actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 20px;
}

.compute-button {
  padding: 12px;
  border: none;
  border-radius: 8px;
  background: linear-gradient(45deg, #667eea, #764ba2);
  color: white;
  font-weight: bold;
  cursor: pointer;
  transition: transform 0.2s;
}

.compute-button:hover:not(:disabled) {
  transform: translateY(-2px);
}

.compute-button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.performance-stats {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.stat {
  display: flex;
  justify-content: space-between;
  padding: 8px;
  background: rgba(0, 255, 255, 0.1);
  border-radius: 4px;
}

.stat-label {
  color: #ccc;
}

.stat-value {
  color: #00ffff;
  font-weight: bold;
}

.parameter-controls {
  display: flex;
  flex-direction: column;
  gap: 15px;
}

.param-group {
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.param-group label {
  color: #ccc;
  font-size: 14px;
}

.param-group input,
.param-group select {
  padding: 8px;
  border: 1px solid #444;
  border-radius: 4px;
  background: #333;
  color: white;
}

.compute-status {
  position: absolute;
  top: 20px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 20px;
  background: rgba(0, 0, 0, 0.8);
  border-radius: 20px;
  color: #00ffff;
}

.spinner {
  width: 16px;
  height: 16px;
  border: 2px solid rgba(0, 255, 255, 0.3);
  border-top: 2px solid #00ffff;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}
</style>
